import os,requests
import re
from django.core.files.base import ContentFile
from django.db import transaction
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from urllib.parse import urlparse
from rest_framework import viewsets, permissions, status,filters,mixins
from rest_framework.response import Response
from rest_framework.parsers import JSONParser,MultiPartParser, FormParser
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework import permissions
from .models import DjDish, DjDishCategory, DjDishImage
from .models import DjChef
from apps.menu import PermissionDenied

class IsChefUser(permissions.BasePermission):
    """验证用户是否是认证厨师"""
    def has_permission(self, request, view):
        return hasattr(request.user, 'chef_profile')
from .serializers import (
    DishSerializer,
    DishCategorySerializer,
    DishCreateUpdateSerializer,
    DishImageSerializer,
    VdjDishCategorySerializer,
    VdjDishCreateUpdateSerializer,
    VdjDishSerializer
)
from apps.chefs.models import DjChef
from core.permissions import IsAdminUser, IsChefOwner
from django.db.models import Prefetch
import logging

logger = logging.getLogger(__name__)


#消费端
class ChefMenuViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    消费端 - 获取厨师菜单
    """
    serializer_class = DishCategorySerializer
    permission_classes = [permissions.AllowAny]

    def get_queryset(self):
        chef_id = self.kwargs['chef_id']
        return DjDishCategory.objects.filter(
            djdish__chef_id=chef_id,
            djdish__is_available=True,
            is_active=True
        ).distinct().prefetch_related(
            Prefetch(
                'djdish_set',
                queryset=DjDish.objects.filter(
                    chef_id=chef_id,
                    is_available=True
                ).prefetch_related(  # 新增：关联查询菜品图片
                    Prefetch(
                        'original_images',  # 对应DjDishImage中related_name
                        queryset=DjDishImage.objects.filter(
                            is_approved=True  # 只获取审核通过的图片
                        ).order_by('-is_primary', 'sort_order')  # 优先主图
                    )
                ).order_by('sort_order'),
                to_attr='available_dishes'
            )
        ).order_by('sort_order')

    @action(detail=False, methods=['get'], url_path='categories')
    def categories(self, request, chef_id=None):
        """获取厨师菜品分类及分类下的菜品信息"""
        categories = self.get_queryset()
        serializer = self.get_serializer(categories, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'], url_path='dishes')
    def dishes(self, request, chef_id=None):
        """获取厨师所有菜品"""
        dishes = DjDish.objects.filter(
            chef_id=chef_id,
            is_available=True
        ).select_related('category').order_by('sort_order')
        serializer = DishSerializer(dishes, many=True)
        return Response(serializer.data)

    def list(self, request, *args, **kwargs):
        """
        重写 list 方法，返回包含分类及分类下菜品的完整菜单数据
        """
        queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
    

class DishCategoryViewSet(viewsets.ReadOnlyModelViewSet):
    """
    菜品分类视图集
    """
    queryset = DjDishCategory.objects.filter(is_active=True)
    serializer_class = DishCategorySerializer
    permission_classes = [permissions.IsAuthenticated]

    def get_queryset(self):
        # 可根据语言参数返回不同语言的分类名称
        return super().get_queryset().order_by('sort_order')

class DishViewSet(viewsets.ModelViewSet):
    """
    菜品管理视图集
    """
    serializer_class = DishSerializer
    permission_classes = [permissions.IsAuthenticated, IsChefOwner]
    parser_classes = [JSONParser,MultiPartParser, FormParser] # 添加对文件上传的支持

    def get_queryset(self):
        # 只返回当前厨师的菜品
        chef = get_object_or_404(DjChef, user=self.request.user)
        return DjDish.objects.filter(chef=chef).select_related('category')

    def get_serializer_class(self):
        if self.action in ['create', 'update', 'partial_update']:
            return DishCreateUpdateSerializer
        return super().get_serializer_class()

    def perform_create(self, serializer):
        # 获取当前用户的厨师profile
        try:
            chef_profile = self.request.user.djchef_profile
            serializer.save(chef=chef_profile)
        except DjChef.DoesNotExist:
            raise PermissionDenied("只有认证厨师可以创建菜品")

    @action(detail=False, methods=['post'])
    def upload_image(self, request):
        logger.info('[后端] 收到图片上传请求')

        if 'image' not in request.FILES:
            logger.error('[后端] 上传请求中没有image文件')
            return Response({'error': 'No image provided'}, status=400)
        
        try:
            image_file = request.FILES['image']
            dish_id = request.POST.get('dish_id')
            
            if not dish_id:
                logger.error('[后端] 缺少dish_id参数')
                return Response({'error': '缺少菜品ID'}, status=400)
            
            # 验证菜品是否存在且属于当前用户
            try:
                dish = DjDish.objects.get(id=dish_id, chef__user=request.user)
            except DjDish.DoesNotExist:
                logger.error(f'[后端] 菜品不存在或无权限，dish_id：{dish_id}')
                return Response({'error': '菜品不存在或无权限'}, status=403)
            
            # 检查文件格式（非PNG仅警告，不阻断）
            if not image_file.name.lower().endswith('.png'):
                logger.warn(f'[后端] 非PNG文件：{image_file.name}')

            # 保存文件（优化：避免重复保存）
            from django.core.files.storage import default_storage
            save_path = f"dj_dish_images/{image_file.name}"
            saved_name = default_storage.save(save_path, image_file)
            
            if not default_storage.exists(saved_name):
                logger.error(f'[后端] 文件保存失败，路径：{saved_name}')
                return Response({'error': '文件保存失败'}, status=500)
            
            # 创建图片记录并关联菜品
            dish_image = DjDishImage.objects.create(
                image=saved_name,
                dish=dish,  # 直接关联对象，避免ID无效
                is_primary=True
            )

            return Response({
                'data': {
                    'id': dish_image.id,
                    'url': default_storage.url(saved_name)
                }
            })
        except Exception as e:
            logger.error(f'[后端] 图片上传异常：{str(e)}', exc_info=True)
            return Response({'error': str(e)}, status=500)
    
    @action(detail=True, methods=['post'])
    def add_image(self, request, pk=None):
        dish = self.get_object()  # 获取菜品实例
        image_id = request.data.get('image_id')
        try:
            dish_image = DjDishImage.objects.get(id=image_id)
            dish.dish_images.add(dish_image)  # 多对多关联
            return Response({'status': 'success'})
        except DjDishImage.DoesNotExist:
            return Response({'error': 'Image not found'}, status=404)

    @action(detail=True, methods=['post'])
    def ai_recognize(self, request, pk=None):
        """
        AI识别菜品
        """
        # 这里可以集成实际的AI识别服务
        from .ai_service import recognize_dish
        try:
            dish = self.get_object()
            image_file = request.FILES.get('image')
            
            if not image_file:
                return Response(
                    {'error': '请上传图片'},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            result = recognize_dish(image_file)
            return Response(result)
            
        except Exception as e:
            logger.error(f'AI识别失败: {str(e)}')
            return Response(
                {'error': '识别失败，请稍后再试'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    @action(detail=True, methods=['post'])
    def toggle_availability(self, request, pk=None):
        """
        切换菜品上架状态
        """
        dish = self.get_object()
        dish.is_available = not dish.is_available
        dish.save()
        return Response({
            'id': dish.id,
            'is_available': dish.is_available
        })
    
    @action(detail=True, methods=['get'], url_path='images')
    def get_images(self, request, pk=None):
        """获取菜品图片（通过外键关联查询）"""
        dish = self.get_object()
        
        try:
            # 使用DjDishImage的外键dish查询（与模型定义一致）
            images = DjDishImage.objects.filter(dish=dish)
            serializer = DishImageSerializer(images, many=True)
            return Response(serializer.data)
        except Exception as e:
            # 打印详细错误日志
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"获取图片失败：{str(e)}", exc_info=True)
            return Response(
                {"error": "获取图片失败", "detail": str(e)}, 
                status=500
            )

    @action(detail=True, methods=['put'], url_path='update-availability')
    def update_availability(self, request, pk=None):
        """PUT方式更新可用状态"""
        dish = self.get_object()
        dish.is_available = not dish.is_available
        dish.save()
        return Response({'is_available': dish.is_available})

    @action(detail=False, methods=['get'])
    def mine(self, request):
        chef = get_object_or_404(DjChef, user=request.user)
        queryset = self.filter_queryset(
            DjDish.objects.filter(chef=chef).select_related('category')
        )
        
        # 支持分页
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
            
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
    
    def create(self, request, *args, **kwargs):
        try:
            # 日志：记录请求开始及原始数据
            logger.info(f"开始创建菜品，请求用户：{request.user.id if request.user.is_authenticated else '匿名用户'}")
            logger.debug(f"原始请求数据：{request.data}，文件：{request.FILES}")  # 新增FILES日志

            data = request.data.copy()
            
            # 1. 处理图片字段（同时兼容URL和直接上传的文件）
            logger.info("开始处理图片字段...")
            # 优先处理request.FILES中的图片（手机真机可能直接上传文件）
            if 'image' in request.FILES:
                logger.info("检测到直接上传的图片文件，从FILES中获取")
                data['image'] = request.FILES['image']
            # 再处理微信临时URL图片（开发环境）
            elif 'image' in data and isinstance(data['image'], str) and data['image'].startswith('http://tmp/'):
                try:
                    logger.info(f"检测到微信临时图片URL：{data['image']}，开始下载...")
                    response = requests.get(data['image'], timeout=10)
                    response.raise_for_status()
                    
                    filename = os.path.basename(urlparse(data['image']).path)
                    file_content = ContentFile(response.content)
                    data['image'] = file_content
                    data['image'].name = filename
                    logger.info(f"临时图片处理成功，文件名：{filename}")
                except requests.exceptions.RequestException as e:
                    logger.error(f"临时图片下载失败：{str(e)}", exc_info=True)
                    return Response(
                        {'error': '图片下载失败，请检查网络'},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                except Exception as e:
                    logger.error(f"临时图片处理异常：{str(e)}", exc_info=True)
                    return Response(
                        {'error': '图片处理失败'},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            else:
                logger.info("未检测到有效图片（非文件或非微信临时URL）")
            
            # 2. 预处理base_price（保持不变）
            logger.info("开始处理价格字段...")
            # （省略价格处理逻辑，与原代码一致）
            
            # 3. 验证分类字段（保持不变）
            logger.info("开始验证分类字段...")
            # （省略分类验证逻辑，与原代码一致）
            
            # 4. 使用修改后的数据调用序列化器
            logger.info("开始序列化器验证...")
            logger.debug(f"处理后的数据：{data}")
            serializer = self.get_serializer(data=data)
            
            try:
                serializer.is_valid(raise_exception=True)
                logger.info("序列化器验证通过，准备保存数据")
            except ValidationError as e:
                logger.error(f"序列化器验证失败：{e.detail}", exc_info=True)
                raise
            
            # 5. 保存数据
            self.perform_create(serializer)
            dish_id = serializer.instance.id
            logger.info(f"菜品创建成功，ID：{dish_id}")
            
            # 6. 若有图片，自动创建DjDishImage关联（如果序列化器未处理）
            if 'image' in data and hasattr(data['image'], 'read'):  # 判断是否为文件对象
                try:
                    # 保存图片到DjDishImage并关联当前菜品
                    dish_image = DjDishImage.objects.create(
                        image=data['image'],
                        dish_id=dish_id,
                        is_primary=True
                    )
                    logger.info(f"图片自动关联成功，图片ID：{dish_image.id}")
                except Exception as e:
                    logger.warning(f"图片自动关联失败：{str(e)}，可手动通过upload_image接口关联")
            
            headers = self.get_success_headers(serializer.data)
            return Response(
                serializer.data,
                status=status.HTTP_201_CREATED,
                headers=headers
            )
            
        except ValidationError:
            raise
        except Exception as e:
            logger.critical("创建菜品时发生未捕获异常", exc_info=True)
            return Response(
                {'error': '服务器内部错误，请稍后重试'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        
    @transaction.atomic  # 确保事务原子性，避免部分删除
    def destroy(self, request, *args, **kwargs):
        dish = self.get_object()
        
        # 1. 删除关联的图片文件和记录
        for dish_image in DjDishImage.objects.filter(dish=dish):
            # 删除实际图片文件
            if dish_image.image and hasattr(dish_image.image, 'storage'):
                try:
                    dish_image.image.storage.delete(dish_image.image.name)
                except Exception as e:
                    print(f"删除图片文件失败: {e}")  # 仅打印，不中断流程
            # 删除图片记录
            dish_image.delete()
        
        # 2. 删除菜品本身
        dish.delete()
        
        return Response(
            {"message": "菜品及关联信息已全部删除"},
            status=status.HTTP_204_NO_CONTENT
        )

    
#厨师端后台部分

class VdjDishCategoryViewSet(viewsets.ModelViewSet):
    """后台菜品分类管理"""
    queryset = DjDishCategory.objects.all()
    serializer_class = VdjDishCategorySerializer
    permission_classes = [IsAdminUser]
    filter_backends = [filters.SearchFilter]
    search_fields = ['name', 'name_en']

class VdjDishViewSet(viewsets.ModelViewSet):
    """后台菜品管理"""
    queryset = DjDish.objects.select_related('chef', 'category').all()
    permission_classes = [IsAdminUser]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter]
    filterset_fields = ['category', 'is_available', 'is_featured']
    search_fields = ['name', 'chef__nickname', 'chef__phone_number']

    def get_serializer_class(self):
        if self.action in ['create', 'update', 'partial_update']:
            return VdjDishCreateUpdateSerializer
        return VdjDishSerializer

    def perform_create(self, serializer):
        instance = serializer.save()